package com.sky.service.impl;

import cn.mybatis.mp.core.sql.executor.chain.DeleteChain;
import cn.mybatis.mp.core.sql.executor.chain.QueryChain;
import com.sky.constant.UserActionConstant;
import com.sky.entity.*;
import com.sky.mapper.*;
import com.sky.service.RecommendationService;
import com.sky.utils.SnowflakeIdWorkerUtil;
import com.sky.vo.RecommendationVO;
import db.sql.api.impl.cmd.basic.OrderByDirection;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.*;
import java.util.stream.Collectors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 图书推荐服务实现类
 * 提供图书推荐相关的功能，包括：
 * 1. 热门图书推荐
 * 2. 相似图书推荐
 * 3. 个性化推荐
 * 4. 用户行为记录
 * 5. 推荐列表更新
 */
@Service
@Slf4j
public class RecommendationServiceImpl implements RecommendationService {

    @Autowired
    private BooksMapper booksMapper;

    @Autowired
    private UserborrowhistoryMapper userborrowhistoryMapper;

    @Autowired
    private UserBookRatingsMapper userBookRatingsMapper ;

    @Autowired
    private UsercollectionsMapper usercollectionsMapper;

    @Autowired
    private BookcategoriesMapper bookcategoriesMapper;

    @Autowired
    private RecommendationsMapper recommendationsMapper;

    @Autowired
    private ThreadPoolExecutor recommendationThreadPool;

    @Autowired
    private UseractionsMapper useractionsMapper;

    @Autowired
    private SnowflakeIdWorkerUtil snowflakeIdWorkerUtil;

    /**
     * 获取热门图书列表
     * 根据图书热度分数降序排序，返回指定数量的热门图书
     *
     * @param limit 返回的图书数量
     * @return 热门图书列表，包含图书基本信息
     */
    @Override
    public List<RecommendationVO> getPopularBooks(Integer limit) {
        // 获取热门图书列表
        List<Books> popularBooks = QueryChain.of(booksMapper)
                .orderBy(OrderByDirection.DESC, Books::getPopularityScore)
                .limit(limit)
                .list();

        // 转换为VO对象
        return popularBooks.stream().map(this::convertToRecommendationVO).collect(Collectors.toList());
    }

    /**
     * 获取相似图书推荐
     * 基于图书分类进行相似图书推荐，步骤如下：
     * 1. 获取目标图书的分类
     * 2. 查找相同分类的其他图书
     * 3. 按热度排序并返回指定数量的图书
     *
     * @param bookId 目标图书ID
     * @param limit 返回的图书数量
     * @return 相似图书列表
     */
    @Override
    public List<RecommendationVO> getSimilarBooks(Integer bookId, Integer limit) {
        // 1. 获取当前图书的分类
        List<Integer> categoryIds = QueryChain.of(bookcategoriesMapper)
                .eq(Bookcategories::getBookId, bookId)
                .list()
                .stream()
                .map(Bookcategories::getCategoryId)
                .collect(Collectors.toList());

        if (categoryIds.isEmpty()) {
            return new ArrayList<>();
        }

        // 2. 获取相同分类的其他图书
        List<Integer> similarBookIds = QueryChain.of(bookcategoriesMapper)
                .in(Bookcategories::getCategoryId, categoryIds)
                .ne(Bookcategories::getBookId, bookId)  // 排除当前图书
                .list()
                .stream()
                .map(Bookcategories::getBookId)
                .distinct()
                .collect(Collectors.toList());

        if (similarBookIds.isEmpty()) {
            return new ArrayList<>();
        }

        // 3. 获取这些图书的详细信息
        List<Books> similarBooks = QueryChain.of(booksMapper)
                .in(Books::getBookId, similarBookIds)
                .orderBy(OrderByDirection.DESC, Books::getPopularityScore)  // 使用正确的排序语法
                .limit(limit)
                .list();

        // 4. 转换为VO对象
        return similarBooks.stream().map(this::convertToRecommendationVO).collect(Collectors.toList());
    }

    /**
     * 记录用户行为
     * 只记录行为，不直接更新热度分数
     * 热度分数由 PopularityScoreTask 统一计算和更新
     *
     * @param userId 用户ID
     * @param bookId 图书ID
     * @param actionType 行为类型（VIEW/COLLECT/BORROW/RATE）
     */
    @Override
    @Transactional
    public void recordUserAction(Integer userId, Integer bookId, String actionType) {
        try {
            // 验证行为类型
            if (!UserActionConstant.isValidAction(actionType)) {
                throw new IllegalArgumentException("Invalid action type: " + actionType);
            }
            
            // 打印实际要插入的值
            log.info("准备插入的行为类型: '{}', 长度: {}", actionType, actionType.length());

            // 记录用户行为
            Useractions userAction = new Useractions();
            userAction.setActionId(snowflakeIdWorkerUtil.nextId());
            userAction.setUserId(userId);
            userAction.setBookId(bookId);
            userAction.setActionType(actionType);
            userAction.setActionTime(new Date());
            useractionsMapper.save(userAction);

            // 2. 触发推荐更新
            updateRecommendations(userId);

            log.info("记录用户行为成功 - 用户ID: {}, 图书ID: {}, 行为类型: {}, 行为ID: {}", 
                    userId, bookId, actionType, userAction.getActionId());
        } catch (Exception e) {
            log.error("记录用户行为失败 - actionType: '{}', length: {}", actionType, actionType.length(), e);
            throw e;
        }
    }

    /**
     * 获取用户个性化推荐
     * 推荐逻辑：
     * 1. 获取用户的借阅历史
     * 2. 获取用户的收藏记录
     * 3. 获取用户的评分记录
     * 4. 分析用户感兴趣的图书分类
     * 5. 基于用户兴趣推荐相关图书
     * 
     * 如果用户没有任何历史记录，则返回热门图书推荐
     *
     * @param userId 用户ID
     * @param limit 推荐图书数量
     * @return 推荐图书列表
     */
    public List<RecommendationVO> getPersonalizedRecommendations(Integer userId, Integer limit) {

        // 1. 获取用户的历史借阅记录
        List<Integer> borrowedBookIds = QueryChain.of(userborrowhistoryMapper)
                .eq(Userborrowhistory::getUserId, userId)
                .list()
                .stream()
                .map(Userborrowhistory::getBookId)
                .collect(Collectors.toList());

        // 2. 获取用户的收藏记录
        List<Integer> collectedBookIds = QueryChain.of(usercollectionsMapper)
                .eq(Usercollections::getUserId, userId)
                .list()
                .stream()
                .map(Usercollections::getBookId)
                .collect(Collectors.toList());

        // 3. 获取用户评分记录
        List<UserBookRatings> ratings = QueryChain.of(userBookRatingsMapper)
                .eq(UserBookRatings::getUserId, userId)
                .list();

        // 如果用户没有任何历史记录，返回热门推荐
        if (borrowedBookIds.isEmpty() && collectedBookIds.isEmpty() && ratings.isEmpty()) {
            return getPopularBooks(limit);
        }

        // 4. 获取用户感兴趣的图书分类
        Set<Integer> userInterestCategories = new HashSet<>();
        
        // 从借阅历史中获取分类
        if (!borrowedBookIds.isEmpty()) {
            userInterestCategories.addAll(
                QueryChain.of(bookcategoriesMapper)
                    .in(Bookcategories::getBookId, borrowedBookIds)
                    .list()
                    .stream()
                    .map(Bookcategories::getCategoryId)
                    .collect(Collectors.toSet())
            );
        }

        // 从收藏记录中获取分类
        if (!collectedBookIds.isEmpty()) {
            userInterestCategories.addAll(
                QueryChain.of(bookcategoriesMapper)
                    .in(Bookcategories::getBookId, collectedBookIds)
                    .list()
                    .stream()
                    .map(Bookcategories::getCategoryId)
                    .collect(Collectors.toSet())
            );
        }

        // 5. 根据用户兴趣分类推荐图书
        if (!userInterestCategories.isEmpty()) {
            // 获取符合用户兴趣的图书ID
            List<Integer> recommendBookIds = QueryChain.of(bookcategoriesMapper)
                    .in(Bookcategories::getCategoryId, userInterestCategories)
                    .notIn(Bookcategories::getBookId, borrowedBookIds)  // 排除已借阅的图书
                    .list()
                    .stream()
                    .map(Bookcategories::getBookId)
                    .distinct()
                    .collect(Collectors.toList());

            if (!recommendBookIds.isEmpty()) {
                List<Books> recommendBooks = QueryChain.of(booksMapper)
                        .in(Books::getBookId, recommendBookIds)
                        .orderBy(OrderByDirection.DESC, Books::getPopularityScore)
                        .limit(limit)
                        .list();

                return recommendBooks.stream().map(book -> {
                    RecommendationVO vo = convertToRecommendationVO(book);
                    return vo;
                }).collect(Collectors.toList());
            }
        }

        // 如果没有找到足够的推荐图书，返回热门推荐
        return getPopularBooks(limit);
    }

    /**
     * 异步更新用户的推荐列表
     * 更新流程：
     * 1. 删除用户旧的推荐记录
     * 2. 生成新的个性化推荐
     * 3. 批量保存推荐记录
     * 
     * 使用线程池异步执行，避免阻塞主线程
     *
     * @param userId 用户ID
     */
    @Override
    public void updateRecommendations(Integer userId) {
        recommendationThreadPool.execute(() -> {
            try {
                log.info("开始更新用户 {} 的推荐列表", userId);
                
                // 1. 删除旧的推荐记录
                DeleteChain.of(recommendationsMapper)
                        .eq(Recommendations::getUserId, userId)
                        .execute();

                // 2. 获取用户的个性化推荐
                List<RecommendationVO> recommendedBooks = getPersonalizedRecommendations(userId, 50);  // 获取50本推荐图书

                // 3. 批量保存新的推荐记录
                if (!recommendedBooks.isEmpty()) {
                    List<Recommendations> recommendations = recommendedBooks.stream()
                            .map(book -> {
                                Recommendations recommendation = new Recommendations();
                                recommendation.setUserId(userId);
                                recommendation.setBookId(book.getBookId());
                                recommendation.setRecommendationDate(new Date());
                                recommendation.setIsClicked(0);
                                recommendation.setIsCollected(0);
                                recommendation.setIsBorrowed(0);
                                return recommendation;
                            })
                            .collect(Collectors.toList());

                    // 使用 MyBatis-MP 的批量插入
                    recommendationsMapper.saveBatch(recommendations);
                }

                log.info("用户 {} 的推荐列表更新完成，共推荐 {} 本图书", userId, recommendedBooks.size());
            } catch (Exception e) {
                log.error("更新用户 {} 的推荐列表失败", userId, e);
            }
        });
    }

    /**
     * 将图书实体转换为推荐VO对象
     * 转换内容包括：
     * - 基本信息（ID、标题、作者）
     * - 图片链接
     * - 图书简介（超过200字会被截断）
     *
     * @param book 图书实体
     * @return 推荐VO对象
     */
    private RecommendationVO convertToRecommendationVO(Books book) {
        RecommendationVO vo = new RecommendationVO();
        vo.setBookId(book.getBookId());
        vo.setTitle(book.getTitle());
        vo.setAuthor(book.getAuthor());
        vo.setCoverImage(book.getCoverImage());
        vo.setDescription(book.getDescription());
        
        // 如果简介太长，可以进行截断
        if (book.getDescription() != null && book.getDescription().length() > 200) {
            vo.setDescription(book.getDescription().substring(0, 197) + "...");
        }
        
        return vo;
    }
} 